<template>
    <div class="main">
        <div ref="sceneNode" class="scene">
        </div>
        <div class="control">
            <select v-model="nowMaterial">
                <option v-for="item in materialList" :value="item.value">{{ item.label }}</option>
            </select>
        </div>
    </div>
</template>

<script setup name="ModelView">
/**
 * @author zhaojiuyi
 * @date 2023/6/22
 * */
import {
    AxesHelper,
    AmbientLight,
    WebGLRenderer,
    Fog, GridHelper,
    Mesh, Clock, Scene,
    MeshStandardMaterial,
    PerspectiveCamera, PlaneGeometry,
    PointLight, Color, BoxGeometry, MeshPhysicalMaterial, PointLightHelper
} from "three"
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
import {onMounted, onUnmounted, ref, watchEffect} from "vue";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";
import {createMaterial, getMaterial, materialList} from "@/components/materialMap";

let timer = null
let gblModel = null
const meshList = []

const sceneNode = ref()
const nowMaterial = ref()
// 渲染器
const renderer = new WebGLRenderer({antialias: true})
renderer.shadowMap.enabled = true


// 场景
const scene = new Scene()
scene.fog = new Fog(0xcccccc, 5, 100);

// 相机
const camera = new PerspectiveCamera()
camera.position.set(5, 5, 5)

// 坐标轴
const axesHelper = new AxesHelper(1000)
scene.add(axesHelper)

// 环境光
const ambientLight = new AmbientLight(0xffffff, 1); // 柔和的白光
scene.add(ambientLight);

// 点光源
const pointLight = new PointLight(0xffffff, 5, 100);
pointLight.position.set(0, 10, 10);
pointLight.castShadow = true
pointLight.shadow.mapSize.width = 5000
pointLight.shadow.mapSize.height = 5000
pointLight.shadow.camera.near = 0.5
pointLight.shadow.camera.far = 5
scene.add(pointLight);

const helper = new PointLightHelper( pointLight, 1 );
scene.add( helper );


// 地面
const geometry = new PlaneGeometry(500, 500, 10, 10);
const material = new MeshStandardMaterial({color: 0x6e6e6e});
const circle = new Mesh(geometry, material);
circle.rotation.x = -Math.PI / 2.0;
circle.receiveShadow = true
scene.add(circle);

// 地面网格
const gridHelper = new GridHelper(500, 200);
scene.add(gridHelper);

// 轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)

// 盒子
const boxGeometry = new BoxGeometry(1,1,1)
const standMaterial = new MeshPhysicalMaterial({color: new Color("gray")})
const cube = new Mesh(boxGeometry,standMaterial)
cube.position.set(-1,0.5,0)
cube.castShadow = true
cube.receiveShadow = true
cube.emissive = 0xffffff
cube.material.metalness = .8
cube.material.roughness = .4
scene.add(cube)

watchEffect(() => {
    const nowMaterialTemp = getMaterial(nowMaterial.value)
    if (!gblModel) return
    console.log(nowMaterialTemp)
    console.log(meshList)
    meshList.forEach(mesh => {
        mesh.material = nowMaterialTemp.material
    })

})

// 时钟
const clock = new Clock()

const render = () => {
    renderer.render(scene, camera)
    controls.update();
    timer = requestAnimationFrame(render)
}

const createModel = () => {
    const loader = new GLTFLoader()
    return new Promise((resolve, reject) => {
        loader.load('/models/Parrot.glb', glb => {
                resolve(glb)
            }, () => {
            },
            err => {
                reject()
            })
    })
}

onMounted(async () => {
    const sceneDom = sceneNode.value
    renderer.setSize(sceneDom.clientWidth, sceneDom.clientHeight)
    sceneDom.innerHTML = null
    sceneDom.appendChild(renderer.domElement)

    gblModel = await createModel()
    console.log(gblModel.scene)
    gblModel.scene.traverse(e => {
        if (e.isMesh) {
            e.castShadow = true
            meshList.push(e)
        }
    })
    createMaterial(meshList[0].material)
    scene.add(gblModel.scene)
    render()
})

onUnmounted(() => {
    cancelAnimationFrame(timer)
})


</script>
<style>
.main {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    display: flex;

}

.scene {
    flex-grow: 3;
    flex-shrink: 0;
    flex-basis: 0;
}

.control {
    flex-grow: 1;
    flex-shrink: 0;
    flex-basis: 0;
}
</style>

